//-----------------------------------------------------------------------
// <copyright file="Stop.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.BizTalk2006.Application
{
    using System.Collections.Generic;
    using System.Globalization;
    using BizTalk.ExplorerOM;
    using BizTalk2004;
    using Build.Framework;

    /// <summary>
    /// Stops an application completely, and terminates any 
    /// </summary>
    /// <remarks>
    /// <code>
    /// <![CDATA[<BizTalk2006.Application.Stop Application="Application Name" Server="server" Database="database" />]]>
    /// </code>
    /// <para>where:</para>
    /// <para><i>Application (Required)</i></para>
    /// <para>
    /// The name of the application to stop.
    /// </para>
    /// <para><i>server</i></para>
    /// <para>
    /// The logical name of the server hosting the BizTalk management database. If neither this nor the
    /// database name are specified then the installation will default to the local installation.
    /// </para>
    /// <para><i>database</i></para>
    /// <para>
    /// The name of the BizTalk management database. If neither this nor the server name are specified 
    /// then the installation will default to the local installation.
    /// </para>
    /// <para><i>username</i></para>
    /// <para>
    /// The username to use to connect to the database if using SQL Server security. The default is to
    /// connect using Windows Integrated security.
    /// </para>
    /// <para><i>password</i></para>
    /// <para>
    /// The password to use to connect to the database if using SQL Server security. The default is to
    /// connect using Windows Integrated security.
    /// </para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Stop" >
    ///         <BizTalk2006.Application.Stop 
    ///             Application="Test Application" 
    ///             Server="." 
    ///             Database="BizTalkMgmtDb" 
    ///              
    ///              />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class Stop : BizTalk2004TaskBase
    {
        private string application;
        private Queue<string> orderedStopped;

        /// <summary>
        /// Constructor of the Stop
        /// </summary>
        public Stop()
        {
            this.orderedStopped = new Queue<string>();
        }

        /// <summary>
        /// The name of the application that will be stopped.
        /// </summary>
        /// <value>The application.</value>
        [Required]
        public string Application
        {
            get { return this.application; }
            set { this.application = value; }
        }

        /// <summary>
        /// This is the main execute method that all tasks should implement
        /// </summary>
        /// <remarks>
        /// TaskException should be thrown in the event of errors
        /// </remarks>
        protected override void InternalExecute()
        {
            this.OrderedApplicationStopped(this.Application);

            using (BtsCatalogExplorer explorer = this.GetBtsCatalogExplorer(this.Server, this.Database))
            {
                foreach (string applicationName in this.orderedStopped)
                {
                    Application app = explorer.Applications[applicationName];

                    foreach (BtsOrchestration orch in app.Orchestrations)
                    {
                        orch.AutoTerminateInstances = true;
                        orch.Status = OrchestrationStatus.Unenlisted;
                        Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Terminated all instances for orchestration: {0}", orch.FullName));
                    }

                    Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Stopping Application: {0}", applicationName));
                    explorer.SaveChanges();
                    ApplicationStopOption option = ApplicationStopOption.DisableAllReceiveLocations | ApplicationStopOption.UndeployAllPolicies | ApplicationStopOption.UnenlistAllOrchestrations | ApplicationStopOption.UnenlistAllSendPortGroups | ApplicationStopOption.UnenlistAllSendPorts;
                    app.Stop(option);
                    explorer.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Create a list with applications in the correct order, to stopped dependant applications.
        /// </summary>
        /// <param name="applicationName">Name of the application.</param>
        private void OrderedApplicationStopped(string applicationName)
        {
            using (BtsCatalogExplorer explorer = this.GetBtsCatalogExplorer(this.Server, this.Database))
            {
                ApplicationCollection apps = explorer.Applications;

                Application app = apps[applicationName];

                // Add dependend applications before deleting the current application.
                foreach (Application referencedApp in app.BackReferences)
                {
                    string appName = referencedApp.Name;

                    // Check 
                    if (!this.orderedStopped.Contains(appName))
                    {
                        this.OrderedApplicationStopped(appName);
                    }
                }

                // Finally delete current application.
                if (!this.orderedStopped.Contains(applicationName))
                {
                    this.orderedStopped.Enqueue(applicationName);
                    Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "OrderedApplicationStopped list Queued application: {0}", applicationName));
                }
            }
        }
    }
}
